package com.yyge.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.function.Function;

public class MybatisUtil {
    //被static修饰的对象是全局共享的
    private static SqlSessionFactory sqlSessionFactory;
    private static final String PATH="mybatis-config.xml";
    // 每个线程都有属于自己的ThreadLocal,底层本质上一个ThreadLocalMap
    private static final  ThreadLocal<SqlSession> sqlSessionThreadLocal=new ThreadLocal<>();
    private static final Logger LOGGER= LoggerFactory.getLogger(MybatisUtil.class);

    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(PATH));
            LOGGER.debug("构建sqlSessionFactory");
        } catch (IOException e) {
            LOGGER.error("构建sqlSessionFactory发生异常",e);
        }
    }

    public static SqlSession openSession(){
        SqlSession session=sqlSessionThreadLocal.get();
        if(session==null){
             // 如果在当前线程的ThreadLocal中还没有缓存过session，则通过SqlSessionFactory创建一个新的sqlSession
           session=sqlSessionFactory.openSession();
           // 将创建好的sqlSession保存到当前线程可见的ThreadLocal中
            sqlSessionThreadLocal.set(session);
            String name =Thread.currentThread().getName();
            LOGGER.debug("创建sqlSession并缓存到" + name + "线程的ThreadLocal中");
        }
        LOGGER.debug("获取SqlSession{}",session);
        return session;
    }

    public static <MAPPER> int updata(Class<MAPPER> mapperClass, Function<MAPPER,Integer> function){
        SqlSession sqlSession=null;
        try {
            sqlSession=openSession();

            // 根据mapperClass得到mybatis的代理对象
            MAPPER mapper = sqlSession.getMapper(mapperClass);

            // 将代理对象交给update方法的调用者来处理
            Integer rows = function.apply(mapper);
            LOGGER.debug("返回数据库受影响的行数{}",rows);

            // 提交事务
            sqlSession.commit();
            LOGGER.debug("提交事务");

            // 返回数据库受影响的行数
            return rows;
        } catch (Exception e){
            // 发生异常，回滚事务
            rollback(sqlSession);
            LOGGER.error("执行update发生异常",e);
        } finally {
            // 关闭sqlSession
            close(sqlSession);
        }
         return 0;
    }

    public static <MAPPER,TARGET> TARGET slect(Class<MAPPER> mapperClass,Function<MAPPER,TARGET> function){
        SqlSession sqlSession=null;
        try {
            sqlSession=openSession();
            // 根据mapperClass得到mybatis的代理对象
            MAPPER mapper= sqlSession.getMapper(mapperClass);
            // 将代理对象交给query方法的调用者
            TARGET target =function.apply(mapper);
            LOGGER.debug("得到查询结果{}",target);
            return target;
        }catch (Exception e){
            LOGGER.error("执行select发生异常",e);
        } finally {
            close(sqlSession);
        }

        return null;
    }

    public static void close(SqlSession sqlSession){
        if(sqlSession!=null){
            sqlSession.close();
            // 在当前线程执行结束时，需要将sqlSession从threadLocal中移除
            sqlSessionThreadLocal.remove();
            LOGGER.debug("关闭sqlSession");
        }
    }
    public static void rollback(SqlSession sqlSession){
        if(sqlSession!=null){
            sqlSession.rollback();
            LOGGER.debug("回滚事务");
        }
    }
}
